import Dexie from 'dexie';
import moment from 'moment';
import cache from './cache';
import { getAllOrgAPI, getAllUserAPI } from '@/services/organization';
import { toBase64, decryptByAES, encryptByAES, getSecretKey, getSecretKeyNew } from './secret';
import localForage from 'localforage';

import config from '@/constant/defaultSettings';
const { MAIN_CONFIG } = config;

// 缓存用户信息 by Id
export interface UserInfoProp {
  id: string;
  userLoginName: string;
  userName: string;
  userType: string;
  organizationId: string;
  isActive: boolean;
  pictureId?: string;
  avatarUrl?: string;
  gender?: string;
  telephone?: string;
  staffNumber?: string;
  mobil?: string;
  [propsname: string]: any;
}
export interface OrganizationInfoProp {
  id: string;
  fullOrgId: string;
  fullOrgName: string;
  orgCode: string;
  orgName: string;
  orgType: string;
  orgSimpleName?: string;
  orgNameEn?: string;
  orgSimpleNameEn?: string;
  telephone?: string;
  fax?: string;
  email?: string;
  description?: string;
  [propsname: string]: any;
}
const { organization, user } = cache;

const fields = [
  'id',
  'orgCode',
  'orgType',
  'orgName',
  'orgSimpleName',
  'orgNameEn',
  'orgSimpleNameEn',
  'telephone',
  'fax',
  'email',
  'description',
];

const getDbStores = (indexDbCrypt: boolean) => {
  if (indexDbCrypt) {
    return { users: 'id', organizations: 'id' };
  }
  return {
    organizations: `id,orgCode,orgName,orgNameEn,orgSimpleName,orgSimpleNameEn,orgType,telephone,fax,email,description,fullOrgId,fullOrgName`,
    users: 'id,userLoginName,userName',
  };
};

class OrganizationDatabase extends Dexie {
  public users: Dexie.Table<UserInfoProp, number>;
  public organizations: Dexie.Table<OrganizationInfoProp, string>;
  public getExpireInfo: () => string[];

  public constructor() {
    super('OrganizationDatabase');

    const indexDbCrypt = MAIN_CONFIG?.indexDbCrypt;
    const suffix = indexDbCrypt ? 'enCrypt' : '';

    this.getExpireInfo = () => {
      const dbExpireTime = localStorage.getItem('dbExpireTime:Organization') || '';
      return dbExpireTime.split('__');
    };

    const checkIsExpired = () => {
      const nowTime = moment().format('YYYY-MM-DD HH:mm:ss');
      const [timeBody, isEnCrypt] = this.getExpireInfo();
      return !timeBody || timeBody < nowTime || isEnCrypt !== suffix;
    };

    const setDbExpireTime = () => {
      const nextTime = moment().add(7, 'days').format('YYYY-MM-DD HH:mm:ss');
      localStorage.setItem('dbExpireTime:Organization', indexDbCrypt ? `${nextTime}__${suffix}` : nextTime);
    };

    this.version(1).stores(getDbStores(indexDbCrypt));
    this.organizations = this.table('organizations');
    this.users = this.table('users');

    if (checkIsExpired()) {
      this.organizations.clear();
      this.users.clear();
      setDbExpireTime();
    }
  }

  private getExpireSecretKey() {
    const expireTime = localStorage.getItem('dbExpireTime:Organization');
    const baseKey = toBase64(moment(expireTime).format('YYYYMMDD'));
    return getSecretKey(baseKey);
  }

  //加密
  encrypt(data: any, otherSkey = '') {
    const sKey = otherSkey || this.getExpireSecretKey();
    return encryptByAES(JSON.stringify(data), sKey, sKey);
  }

  //解密
  decrypt(cipherText: string, defaultValue: any = {}) {
    const sKey = this.getExpireSecretKey();
    try {
      return JSON.parse(decryptByAES(cipherText, sKey, sKey));
    } catch (err) {
      return defaultValue;
    }
  }
  //手动解密
  decryptMannualSkey(cipherText: string, sKey: string, defaultValue: any = {}) {
    try {
      return JSON.parse(decryptByAES(cipherText, sKey, sKey));
    } catch (err) {
      return defaultValue;
    }
  }
  //获取时间秘钥
  getDateSecretKey(expireTime: number) {
    return getSecretKeyNew(expireTime);
  }

  //获取table数据
  async getTableList(table: Dexie.Table) {
    const list = await table.toArray();
    if (!MAIN_CONFIG?.indexDbCrypt) return list;
    return list.map((item: any) => this.decrypt(item.value));
  }

  //list数据存储
  addTableList(table: Dexie.Table, list: any) {
    if (!MAIN_CONFIG?.indexDbCrypt) {
      table.bulkAdd(list);
      return;
    }
    const cryptList = list.map((item: any) => ({
      id: item.id,
      value: this.encrypt(item),
    }));
    table.bulkAdd(cryptList);
  }

  async setItem(key: string, obj: any, outtime?: number) {
    const ctime = parseInt(Date.now() / 1000); //获取存数据的时间
    const exp = outtime || 0; //outtime 是 秒为单位的过期时间
    const outObj = {
      // 时间和数据
      outime: ctime + exp,
      data: this.encrypt(obj),
    };
    return await localForage.setItem(key, outObj);
  }

  async getItem(key: string) {
    const res = await localForage.getItem(key);
    //初始化没有数据
    if (!res) {
      return false;
    }
    //判断过期时间 和获取数据的时间对比 大于过期时间说明超时
    if (res.outime >= parseInt(Date.now() / 1000)) {
      return await this.decrypt(res.data);
    } else {
      return false;
    }
  }
}

export const organizationDB = new OrganizationDatabase();

/**
 *  缓存组织机构信息
 *
 * @param {string} id 组织机构id
 * @param {UserGroupInfoProp} data 组织机构信息对象
 */
export const setOrganization = ({ id, data }: { id: string; data: OrganizationInfoProp }) => {
  organization.set(id, data);
};

/**
 *  获取指定组织机构item的指定字段值
 *
 * @param {string} id 组织机构id
 * @param {string} field 组织机构信息对象
 */
export const getOrganizationField = ({ id, field = 'orgName' }: { id: string; field?: string }) => {
  const organizationInfo = organization.get(id);
  if (!organizationInfo) return '';
  return organizationInfo[field] || '';
};

/**
 *  获取指定组织机构信息
 *
 * @param {string} id 组织机构id
 */
export const getOrganizationInfo = (id: string) => {
  const organizationInfo = organization.get(id);
  if (!organizationInfo) return {};
  return organizationInfo;
};

//拷贝组织机构信息字段
const copyOrganizationByFields = (org: any = {}) => {
  const obj = {};
  for (let i = 0; i < fields.length; i++) {
    const target = org[fields[i]];
    if (target) {
      obj[fields[i]] = target;
    }
  }
  return obj;
};

/**
 *  更新新建的组织机构到缓存
 *
 * @param {OrganizationInfoProp} values 组织机构信息
 */
export const updateOrganizationCacheByCreate = (values: OrganizationInfoProp) => {
  const { id, parentOrgId, orgName } = values;
  const data: any = copyOrganizationByFields(values);
  if (parentOrgId == 'ROOT') {
    setOrganization({
      id,
      data: { ...data, fullOrgId: `ROOT-${id}`, fullOrgName: orgName },
    });
  } else {
    const parentItem = organization.get(parentOrgId);
    if (!parentItem) return;
    setOrganization({
      id,
      data: {
        ...data,
        fullOrgId: `${parentItem.fullOrgId}-${id}`,
        fullOrgName: `${parentItem.fullOrgName} - ${orgName}`,
      },
    });
  }
};

/**
 *  更新已存在的组织机构缓存
 *
 * @param {OrganizationInfoProp} values 组织机构信息
 */
export const updateOrganizationCacheByUpdate = (values: OrganizationInfoProp) => {
  const organizationInfo = organization.get(values.id);
  setOrganization({ id: values.id, data: { ...organizationInfo, ...values } });
};

/**
 *  移除组织机构对应缓存
 *
 * @param {string} key 组织机构缓存的标识键值
 * @param {boolean} removeAll 是否移除所有缓存信息
 */
export const removeOrganization = ({ key, removeAll = false }: { key: string; removeAll?: boolean }) => {
  if (removeAll) {
    organization.remove();
    return;
  }
  key && organization.remove(key);
};

//把model里的用户和组织数据存在indexDb
export const blukIndexDb = async () => {
  try {
    // const count = await organizationDB.users.count();
    // const { listOrganizations, listUsers } = getModelData("organization");
    const orgs: any = await getAllOrgAPI();
    const users: any = await getAllUserAPI();
    users.forEach((u: any) => {
      user.set(u.id, u);
    });
    organizationDB.addTableList(organizationDB.organizations, orgs);
    organizationDB.addTableList(organizationDB.users, users);
  } catch (error) {
    console.error(error);
  }
};
